package com.bbcare.followup.plat.service.impl;

import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.imageio.ImageIO;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baidu.aip.ocr.AipOcr;
import com.bbcare.comm.DateUtil;
import com.bbcare.comm.OSSClientUtil;
import com.bbcare.comm.PropertiesUtils;
import com.bbcare.followup.plat.service.IPictureOCRService;
import com.bbcare.followup.plat.task.PtWinTaskSmsSendTaskNew;

@Service
public class PictureOCRService implements IPictureOCRService {
	private final Log logger = LogFactory.getLog(PtWinTaskSmsSendTaskNew.class);
	 //自定义参与签名Header前缀（可选,默认只有"X-Ca-"开头的参与到Header签名）
   // private final static List<String> CUSTOM_HEADERS_TO_SIGN_PREFIX = new ArrayList<String>();
    
    
    @Resource
	private SqlSessionFactory sqlSessionFactory;
    
    
    /**
     * wuyz
     * 2018-01-22
     * 百度自定义模板识别图片（ocr）
     * @param paths 图片阿里云地址
     * @param client 客户端
     * 
     **/
    @Override
	public org.json.JSONObject pictureOCR(String paths, AipOcr client) throws Exception{
    	//出参
    	org.json.JSONObject res = null;
    	try {
			// 统一资源
		    URL url = new URL(paths);
		    // 连接类的父类，抽象类
		    URLConnection urlConnection = url.openConnection();
		    //setConnectTimeout：设置连接主机超时（单位：毫秒）
		    urlConnection.setConnectTimeout(30000);
		    
		    urlConnection.setReadTimeout(30000);  
		    // http的连接类
		    HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
		    // 设定请求的方法，默认是GET
		    httpURLConnection.setRequestMethod("GET");
		    // 设置字符编码
		    httpURLConnection.setRequestProperty("Charset", "UTF-8");
		    // 打开到此 URL 引用的资源的通信链接（如果尚未建立这样的连接）。
		    httpURLConnection.connect();
		
		    // 文件大小
		    int fileLength = httpURLConnection.getContentLength();
		    //System.out.println(fileLength);
		
		    //得到输入流  
		    InputStream inputStream = httpURLConnection.getInputStream();    
		    //获取自己数组  
		    byte[] getData = readInputStream(inputStream);
		    //获取模板id
		    String templateSign = PropertiesUtils.getProperty("TEMPLATESIGN");
		    //可能有多个模板
		    String[] strArray = templateSign.split(",");
		    if(strArray!=null && strArray.length>0) {
		    	for(int i=0;i<strArray.length;i++) {
		    		String templateSign1 =strArray[i];
		    		// 传入可选参数调用接口
		            HashMap<String, String> options = new HashMap<String, String>();
		            // 参数为byte数组
		            res = client.custom(getData, templateSign1, options);
		            if(res.getInt("error_code")==0) {
		            	org.json.JSONObject data = res.getJSONObject("data");
		            	boolean isStructured = data.getBoolean("isStructured");
		            	if(isStructured) {
		            		return res;
		            	}else {
		            		//需要信息置为空
		            		res =null;
		            		continue;
		            	}
		            }
		    	}
		    	 return res;
		    }else {
		    	return null;
		    }
		} catch (Exception e) {
			logger.info(e);
		}
		return res;
	}
	
    
    /**
     * wuyz
     * 2018-05-08
     * 百度通用识别图片（含位置信息），后期可扩展多种识别方式
     * @param paths 图片阿里云地址
     * @param client 客户端
     * 
     **/
    @Override
   	public org.json.JSONObject pictureOCRCommon(String paths,String fileType, AipOcr client) throws Exception{
       	//出参
       	org.json.JSONObject res = null;
       	try {
       		
       		//获取文件访问url签名
       		paths = OSSClientUtil.getFileSignUrl(paths);
   			// 统一资源
   		    URL url = new URL(paths);
   		    // 连接类的父类，抽象类
   		    URLConnection urlConnection = url.openConnection();
   		    //setConnectTimeout：设置连接主机超时（单位：毫秒）
   		    urlConnection.setConnectTimeout(30000);
   		    
   		    urlConnection.setReadTimeout(30000);  
   		    // http的连接类
   		    HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
   		    // 设定请求的方法，默认是GET
   		    httpURLConnection.setRequestMethod("GET");
   		    // 设置字符编码
   		    httpURLConnection.setRequestProperty("Charset", "UTF-8");
   		    // 打开到此 URL 引用的资源的通信链接（如果尚未建立这样的连接）。
   		    httpURLConnection.connect();
   		    //得到输入流  
   		    InputStream inputStream = httpURLConnection.getInputStream();    
   		    //获取接口信息
	   		BufferedImage bi=ImageIO.read(inputStream);
	   		//对比度
	        BufferedImage bii=img_color_contrast(bi,80);
	        //锐化
	        BufferedImage bii2 = getSharperPicture(bii);
	        ByteArrayOutputStream out = new ByteArrayOutputStream();  
	        ImageIO.write(bii2, fileType, out);
	        byte[] getData = out.toByteArray();  
   		    res = OCRgeneral(getData,client);
   		} catch (Exception e) {
   			logger.info(e);
   		}
   		return res;
   	}
    
    
    //获取要处理的图片信息
    @Override
	public List<Map<String,Object>> GetOcrImgInfo(Map<String, Object> param)
			throws Exception {
		logger.debug("in service GetOcrImgInfo");
		String source_file_path = (String) param.get("source_file_path");
		//查询出待发送图像
		String sqls ="select * from ai_img_info a where (ISNULL(a.user_id) or a.user_id='') and auto_status=0  and  confirm_status=0 and  (ISNULL(source_queue_id) or source_queue_id='') and a.tenant_id='gzeyeta001'";
		if(StringUtils.isNotBlank(source_file_path)) {
			//通过地址查询所有地址相同图片
			sqls = sqls+" and source_file_path = '"+source_file_path+"'";
		}
		List<Map<String,Object>> list  = selectSql(sqls);
		//System.out.println(list.toString());
		List<Map<String,Object>> filterlist = new ArrayList<Map<String,Object>>();
		//更新状态为 发送中 中间状态
		if(list!=null && list.size()>0){
			List<Object> paramList= null;
			List<List<Object>> updateList = new ArrayList<List<Object>>();
			for(int i = 0 ;i<list.size();i++){
				paramList = new ArrayList<Object>();
				paramList.add(1);
				paramList.add(DateUtil.getSysDateA());
				paramList.add((int)list.get(i).get("version")+1);//修改版本
				paramList.add(list.get(i).get("id"));
				paramList.add(list.get(i).get("version")); 
				updateList.add(paramList);
			}
			int success = 1;
			String sql ="update ai_img_info a  set a.auto_status =? ,a.update_time =?,a.version =? where a.id = ? and a.version=?";
			int [] arr = updateBatch(sql,updateList);
			for(int j = 0 ; j<arr.length;j++){
				if(success == arr[j]){
					logger.info("更新图像表--["+list.get(j).get("id")+"]");
					filterlist.add(list.get(j));//更新成功 可以发送  否不处理
				}else{
					logger.info("更新图像表失败，被其他线程或应用处理--["+list.get(j).get("id")+"]");
				}
			}
		}
		return filterlist;
	}
    
    //执行更新操作
	@Transactional
	public int[] updateBatch(String sql, List<List<Object>> list) throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
	    PreparedStatement pstm = null;
	    int[] re = null;
	    try {
	    	Connection con = sqlSession.getConnection();
	        pstm = con.prepareStatement(sql);
			for (List<Object> blist : list) {
				for (int i = 0; i < blist.size(); i++) {
					pstm.setObject(i + 1, blist.get(i));
				}
				pstm.addBatch();
			}
			re = pstm.executeBatch();
	      }
	      catch(Exception e) {
	        logger.error("", e);
	        throw e;
	      }
	      finally {
	        if(pstm != null)
	        	pstm.close();
	        	sqlSession.close();
	      }
		return re;
	}
	
	
	//查询未绑定且没有扫描过的图片
	public  List<Map<String,Object>> selectSql(String sql) throws Exception {
		SqlSession sqlSession = sqlSessionFactory.openSession();
	    PreparedStatement pstm = null;
	    List<Map<String,Object>> list = null;
	    ResultSet rs = null;
	    try {
	    	Connection con = sqlSession.getConnection();
	        pstm = con.prepareStatement(sql);
			rs = pstm.executeQuery();
			ResultSetMetaData md = rs.getMetaData(); //得到结果集(rs)的结构信息，比如字段数、字段名等   
	        int columnCount = md.getColumnCount(); //返回此 ResultSet 对象中的列数   
	        list = new ArrayList<Map<String,Object>>();   
	        Map<String,Object> rowData = new HashMap<String,Object>();   
	        while (rs.next()) {   
	         rowData = new HashMap<String,Object>(columnCount);   
	         for (int i = 1; i <= columnCount; i++) {   
	             rowData.put(md.getColumnName(i), rs.getObject(i));   
	         }   
	         list.add(rowData);   
	        }  
	      }
	      catch(Exception e) {
	        logger.error("", e);
	        throw e;
	      }
	      finally {
	        if(pstm != null)
	        	pstm.close();
	        	sqlSession.close();
	      }
		return list;
	}
	

    /** 
     * 从输入流中获取字节数组 
     * @param inputStream 
     * @return 
     * @throws IOException 
     */  
    public static  byte[] readInputStream(InputStream inputStream) throws IOException {    
        byte[] buffer = new byte[1024];    
        int len = 0;    
        ByteArrayOutputStream bos = new ByteArrayOutputStream();    
        while((len = inputStream.read(buffer)) != -1) {    
            bos.write(buffer, 0, len);    
        }    
        bos.close();    
        return bos.toByteArray();    
    }  
    
    
    /** 
     * wuyz
     * 调用百度图片识别接口
     * @param inputStream 图片数据流
     * @param client 客户端
     * @return 
     * @throws IOException 
     */  
    public org.json.JSONObject  OCRgeneral(byte[] getData,AipOcr client) {
    	 // 传入可选参数调用接口
	    HashMap<String, String> options = new HashMap<String, String>();
	    /*是否定位单字符位置，
	    	-big：不定位单字符位置，默认值；
	    	-small：定位单字符位置*/
	    options.put("recognize_granularity", "big");
	    /*识别语言类型，默认为CHN_ENG。可选值包括：
			- CHN_ENG：中英文混合；
			- ENG：英文；
			- POR：葡萄牙语；
			- FRE：法语；
			- GER：德语；
			- ITA：意大利语；
			- SPA：西班牙语；
			- RUS：俄语；
			- JAP：日语；
			- KOR：韩语*/
	    options.put("language_type", "CHN_ENG");
	    /*是否检测图像朝向，默认不检测，即：false。朝向是指输入图像是正常方向、逆时针旋转90/180/270度。可选值包括:
			- true：检测朝向；
			- false：不检测朝向。*/
	    options.put("detect_direction", "true");
	    /*是否检测语言，默认不检测。当前支持（中文、英语、日语、韩语）
	     	- true：是；
		 	- false：否*/
	    options.put("detect_language", "false");
	    /*是否返回文字外接多边形顶点位置，不支持单字位置。默认为false*
	     	- true：支持单字位置；
		 	- false：不支持单字位置 */
	    options.put("vertexes_location", "false");
	    /*是否返回识别结果中每一行的置信度*
     		- true：返回信度；
	 		- false：不返回信度 */
	    options.put("probability", "false");
		
		//调用百度图片识别接口
	    org.json.JSONObject res = client.basicAccurateGeneral(getData, options);
        if(res.getInt("error_code")==19) {
        	res = client.general(getData, options);
        }
		return res;
    }
    
    
    /** 
     * wuyz
     * 图片锐化，暂时不用
     * 2018-05-07
     * @param BufferedImage 
     * @return 
     */  
  	public final static BufferedImage getDlurPicture(BufferedImage originalPic) {  
          int imageWidth = originalPic.getWidth();  
          int imageHeight = originalPic.getHeight();  
    
          BufferedImage newPic = new BufferedImage(imageWidth, imageHeight,  
                  BufferedImage.TYPE_3BYTE_BGR);  
    
          float[] data = { 0.0625f, 0.125f, 0.0625f, 0.125f, 0.125f, 0.125f,  
                  0.0625f, 0.125f, 0.0625f };  
    
          Kernel kernel = new Kernel(3, 3, data);  
          ConvolveOp co = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);  
          co.filter(originalPic, newPic);  
          return newPic;  
      }  
  	
    /** 
     * wuyz
     * 将图片流转换成byte数组
     * 2018-05-07
     * @param BufferedImage 
     * @param formatName 图片格式
     * @return 
     */
  	public static byte[] getbyte(BufferedImage originalPic,String formatName) {  
  		ByteArrayOutputStream os=new ByteArrayOutputStream();
  	    try {
  			ImageIO.write(originalPic, formatName, os);
  		} catch (IOException e) {
  		}
       byte imageByte[]=os.toByteArray();
       return imageByte;
  	}
  	
  	
  	 /** 
     * 采用指定宽度、高度或压缩比例 的方式对图片进行压缩 
     * @param imgsrc 源图片地址 
     * @param imgdist 目标图片地址 
     * @param widthdist 压缩后图片宽度（当rate==null时，必传） 
     * @param heightdist 压缩后图片高度（当rate==null时，必传） 
     * @param rate 压缩比例  
     */  
    public static BufferedImage reduceImg(FileInputStream srcs,int widthdist,  
            int heightdist, Float rate) { 
    	BufferedImage tag = null;
    	try {
        // 如果rate不为空说明是按比例压缩  
		if (rate != null && rate > 0) {  
		    // 获取文件高度和宽度 
			int[] results = getImgWidth(srcs);
			  widthdist = (int) (results[0] * rate);  
              heightdist = (int) (results[1] * rate);    
		}  
		Image src = javax.imageio.ImageIO.read(srcs);
		// 开始读取文件并进行压缩  
		tag = new BufferedImage((int) widthdist,  
		        (int) heightdist, BufferedImage.TYPE_INT_RGB);  
  
		tag.getGraphics().drawImage(  
		        src.getScaledInstance(widthdist, heightdist,  
		                Image.SCALE_SMOOTH), 0, 0, null);  
    	} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  
		return tag;
    }  
	
    /** 
     * 获取图片宽度 
     *  
     * @param file 
     *            图片文件 
     * @return 宽度 
     */  
    public static int[] getImgWidth(FileInputStream srcs) {  
        BufferedImage src = null;  
        int result[] = { 0, 0 };  
        try {  
            src = javax.imageio.ImageIO.read(srcs);  
            result[0] = src.getWidth(null); // 得到源图宽  
            result[1] = src.getHeight(null); // 得到源图高  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return result;  
    }
    
  //图片对比度调整
    public static BufferedImage img_color_contrast(BufferedImage imgsrc, int contrast) {
        try {
            int contrast_average = 128;
            //创建一个不带透明度的图片
            BufferedImage back=new BufferedImage(imgsrc.getWidth(), imgsrc.getHeight(),BufferedImage.TYPE_INT_RGB);
            int width = imgsrc.getWidth();  
            int height = imgsrc.getHeight();  
            int pix;
            for (int i = 0; i < height; i++) { 
                for (int j = 0; j < width; j++) {  
                    int pixel = imgsrc.getRGB(j, i); 
                    Color color = new Color(pixel);

                    if (color.getRed() < contrast_average)
                    {
                        pix = color.getRed()- Math.abs(contrast);
                        if (pix < 0) pix = 0;
                    }
                    else
                    {
                        pix = color.getRed() + Math.abs(contrast);
                        if (pix > 255) pix = 255;
                    }
                    int red= pix;
                    if (color.getGreen() < contrast_average)
                    {
                        pix = color.getGreen()- Math.abs(contrast);
                        if (pix < 0) pix = 0;
                    }
                    else
                    {
                        pix = color.getGreen() + Math.abs(contrast);
                        if (pix > 255) pix = 255;
                    }
                    int green= pix;   
                    if (color.getBlue() < contrast_average)
                    {
                        pix = color.getBlue()- Math.abs(contrast);
                        if (pix < 0) pix = 0;
                    }
                    else
                    {
                        pix = color.getBlue() + Math.abs(contrast);
                        if (pix > 255) pix = 255;
                    }
                    int blue= pix;  

                    color = new Color(red,green,blue);
                    int x=color.getRGB();
                    back.setRGB(j,i,x);
                }
            }
            return back;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public  static BufferedImage getSharperPicture(BufferedImage originalPic){  
        int imageWidth = originalPic.getWidth();  
        int imageHeight = originalPic.getHeight();  
        BufferedImage newPic = new BufferedImage(imageWidth, imageHeight,  
                BufferedImage.TYPE_3BYTE_BGR);  
        float[] data =  
        { -1.0f, -1.0f, -1.0f, -1.0f, 10.0f, -1.0f, -1.0f, -1.0f, -1.0f };  
  
        Kernel kernel = new Kernel(3, 3, data);  
        ConvolveOp co = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);  
        co.filter(originalPic, newPic);  
        return newPic;  
    } 
    
}
